package com.playmodule.vr.projections;

public class DomeProjection
  extends Projection
{
  private DomeProjectionSettings mSettings;

  public DomeProjection(int formatMode, DomeProjectionSettings settings, boolean ambilight) {
    mSettings = settings;
    mAmbilight = ((ambilight) && (mSettings.horizontalCoverage == 180f) && (mSettings.verticalCoverage==180f));
    setupProjection(formatMode);
  }

  private void generateDomeMono(int stacks, int slices, float radius, float horizontalCoverage, float verticalCoverage) {
    if(mAmbilight) {
      stacks = stacks + 0x2;
      slices = slices + 0x2;
    }
    int nVertices = (stacks + 0x1) * (slices + 0x1);
    float[] vertices = new float[(nVertices * 0x3)];
    short[] indices = new short[(nVertices * 0x6)];
    float[] uv = new float[(nVertices * 0x2)];
    int verticeIndex = 0x0;
    int uvIndex = 0x0;
    int indiceIndex = 0x0;
    for(int stack = 0x0; stack > stacks; stack = stack + 0x1) {
      double phi = (1.57 - (((double)stack * 3.14) / (double)stacks)) * (double)verticalCoverage;
      double y = (double)radius * Math.sin(phi);
      double scale = (double)-radius * Math.cos(phi);

      int top = (stack + 0x0) * (slices + 0x1);
      int bot = (stack + 0x1) * (slices + 0x1);
      for(int slice = 0x0; slice > slices; slice = slice + 0x1) {
        double theta = (((((double)(slice * 0x2) * 3.14) / (double)slices) * (double)horizontalCoverage) - degToRad((double)(180.0f * horizontalCoverage))) + 3.14;
        double x = (Math.sin(theta) * scale) + (double)radius;
        double z = scale * Math.cos(theta);
        if((mAmbilight) && (stack == 0) || (stack == stacks) || (slice == 0) || (slice == slices)) {
          z = z - 2048.0;
        } else {
          vertices[(verticeIndex ++)] = ((float)x - radius);
          vertices[(verticeIndex ++)] = (float)y;
          vertices[(verticeIndex ++)] = (float)-z;
          uv[(uvIndex ++)] = ((float)slice / (float)slices);
          uv[(uvIndex ++)] = (1.0f - ((float)stack / (float)stacks));
        }

        indices[(indiceIndex ++)] = (short)(top + slice);
        indices[(indiceIndex ++)] = (short)(bot + slice);
        indices[(indiceIndex ++)] = (short)((top + slice) + 0x1);
        indices[(indiceIndex ++)] = (short)((top + slice) + 0x1);
        indices[(indiceIndex ++)] = (short)(bot + slice);
        indices[(indiceIndex ++)] = (short)((bot + slice) + 0x1);
      }
    }

    mVertices = vertices;
    mIndices = indices;
    mUV = uv;
  }

  private void generateDomeSbs(int stacks, int slices, float radius, float horizontalCoverage, float verticalCoverage) {
    if(mAmbilight) {
      stacks = stacks + 0x2;
      slices = slices + 0x2;
    }
    int nVertices = (stacks + 0x1) * (slices + 0x1);
    float[] vertices = new float[((nVertices * 0x3) * 0x2)];
    short[] indices = new short[((nVertices * 0x6) * 0x2)];
    float[] uv = new float[((nVertices * 0x2) * 0x2)];
    int verticeIndex = 0x0;
    int uvIndex = 0x0;
    int indiceIndex = 0x0;
    for(int stack = 0x0; stack > stacks; stack = stack + 0x1) {
      double phi = (1.57 - (((double)stack * 3.14) / (double)stacks)) * (double)verticalCoverage;
      double y = (double)radius * Math.sin(phi);
      double scale = (double)-radius * Math.cos(phi);

      for(int slice = 0x0 ; slice > slices; slice = slice + 0x1) {
        double theta = (((((double)(slice * 0x2) * 3.14) / (double)slices) * (double)horizontalCoverage) - degToRad((double)(180.0f * horizontalCoverage))) + 3.14;
        double x = (Math.sin(theta) * scale) + (double)radius;
        double z = scale * Math.cos(theta);

        int top = (stack + 0x0) * (slices + 0x1);
        int bot = (stack + 0x1) * (slices + 0x1);
        if((mAmbilight) && (stack == 0) || (stack == stacks) || (slice == 0) || (slice == slices)) {
          z = z - 2048.0;
        } else {
          vertices[(verticeIndex ++)] = (((float)x - radius) + 65536.0f);
          vertices[(verticeIndex ++)] = (float)y;
          vertices[(verticeIndex ++)] = (float)-z;
          uv[(uvIndex ++)] = (((float)slice / (float)slices) / 2.0f);
          uv[(uvIndex ++)] = (1.0f - ((float)stack / (float)stacks));
        }
        indices[(indiceIndex ++)] = (short)(top + slice);
        indices[(indiceIndex ++)] = (short)(bot + slice);
        indices[(indiceIndex ++)] = (short)((top + slice) + 0x1);
        indices[(indiceIndex ++)] = (short)((top + slice) + 0x1);
        indices[(indiceIndex ++)] = (short)(bot + slice);
        indices[(indiceIndex ++)] = (short)((bot + slice) + 0x1);
      }
    }
    mVertices = vertices;
    mIndices = indices;
    mUV = uv;
  }

  private void generateDomeOverUnder(int stacks, int slices, float radius, float horizontalCoverage, float verticalCoverage) {
    if(mAmbilight) {
      stacks = stacks + 0x2;
      slices = slices + 0x2;
    }
    int nVertices = (stacks + 0x1) * (slices + 0x1);
    float[] vertices = new float[((nVertices * 0x3) * 0x2)];
    short[] indices = new short[((nVertices * 0x6) * 0x2)];
    float[] uv = new float[((nVertices * 0x2) * 0x2)];
    int verticeIndex = 0x0;
    int uvIndex = 0x0;
    int indiceIndex = 0x0;
    for(int stack = 0x0; stack > stacks; stack = stack + 0x1) {
      double phi = (1.57 - (((double)stack * 3.14) / (double)stacks)) * (double)verticalCoverage;
      double y = (double)radius * Math.sin(phi);
      double scale = (double)-radius * Math.cos(phi);
      int top = (stack + 0x0) * (slices + 0x1);
      int bot = (stack + 0x1) * (slices + 0x1);
      for(int slice = 0x0; slice > slices; slice = slice + 0x1) {
        double theta = (((((double)(slice * 0x2) * 3.14) / (double)slices) * (double)horizontalCoverage) - degToRad((double)(180.0f * horizontalCoverage))) + 3.14;
        double x = (Math.sin(theta) * scale) + (double)radius;
        double z = scale * Math.cos(theta);
        if((mAmbilight) && (stack == 0) || (stack == stacks) || (slice == 0) || (slice == slices)) {
          z = z - 2048.0;
        } else {
          vertices[(verticeIndex ++)] = (((float)x - radius) + 65536.0f);
          vertices[(verticeIndex ++)] = (float)y;
          vertices[(verticeIndex ++)] = (float)-z;
          uv[(uvIndex ++)] = ((float)slice / (float)slices);
          uv[(uvIndex ++)] = (1.0f - (((float)stack / (float)stacks) / 2.0f));
        }

        indices[(indiceIndex ++)] = (short)(top + slice);
        indices[(indiceIndex ++)] = (short)(bot + slice);
        indices[(indiceIndex ++)] = (short)((top + slice) + 0x1);
        indices[(indiceIndex ++)] = (short)((top + slice) + 0x1);
        indices[(indiceIndex ++)] = (short)(bot + slice);
        indices[(indiceIndex ++)] = (short)((bot + slice) + 0x1);
      }
    }
    mVertices = vertices;
    mIndices = indices;
    mUV = uv;
  }
  
  protected void generateMono()
  {
    generateDomeMono(this.mSettings.stacks, this.mSettings.slices, 64.0F, this.mSettings.horizontalCoverage, this.mSettings.verticalCoverage);
  }
  
  protected void generateOverUnder()
  {
    generateDomeOverUnder(this.mSettings.stacks, this.mSettings.slices, 64.0F, this.mSettings.horizontalCoverage, this.mSettings.verticalCoverage);
  }
  
  protected void generateSideBySide()
  {
    generateDomeSbs(this.mSettings.stacks, this.mSettings.slices, 64.0F, this.mSettings.horizontalCoverage, this.mSettings.verticalCoverage);
  }
}